﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using BoolanElement;
using BoolanSlide.Document.Format.Helper;
using BoolanSlide.FileStruct;
using BoolanSlide.Language;
using Configuration;
using Windows.Data.Xml.Dom;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;

namespace BoolanElement.Storage
{
    public class BPTFile
    {
        public static async Task<BooDocumentInMemory> OpenFile(StorageFile srcFile)
        {
            BooDocumentInMemory document = new BooDocumentInMemory();
            document.FileName = srcFile.Name;
            using (IRandomAccessStream stream = await srcFile.OpenAsync(FileAccessMode.Read))
            {
                using (DataReader reader = new DataReader(stream.GetInputStreamAt(0)))
                {
                    await reader.LoadAsync((uint)stream.Size);
                    BPTFileBlock summary = await BPTFileBlock.FromArchiveAsync(reader);
                    document.summaryBlock = summary;
                    while (true)
                    {
                        BPTFileBlock block = await BPTFileBlock.FromArchiveAsync(reader);
                        if (block != null)
                        {
                            if (block.GroupName == "slides")
                                document.SlideBlocks.Add(block);
                            else if (block.GroupName == "images")
                            {
                                document.ImageBlocks.Add(block);
                            }
                            else if (block.GroupName == "thumb")
                                document.ThumbBlock = block;

                        }
                        else
                            return document;
                    }
                }
            }
            return document;
        }

        public static async Task<BooDocumentInMemory> CreateNewFile(BPTFileInformation TemplateFileInformation)
        {
            BooDocumentInMemory doc= new BooDocumentInMemory();

            XmlDocument xml = new XmlDocument();
            XmlElement xmlroot = xml.CreateElement("BoolanPPT");
            xml.AppendChild(xmlroot);
            XmlElement count = xml.CreateElement("Count");
            xmlroot.AppendChild(count);
            count.InnerText = "0";

            XmlElement FileName = xml.CreateElement("FileName");
            FileName.InnerText = "DefaultName";
            xmlroot.AppendChild(FileName);

            XmlElement Resolution = xml.CreateElement("Resolution");
            Resolution.InnerText = ((int)Configuration.FileAttributes.Ratio).ToString();
            xmlroot.AppendChild(Resolution);

            XmlElement StorageName = xml.CreateElement("StorageName");
            xmlroot.AppendChild(StorageName);

            XmlElement ThemeGUID = xml.CreateElement("ThemeGUID");
            ThemeGUID.InnerText = TemplateFileInformation.StorageName;
            xmlroot.AppendChild(ThemeGUID);

            StorageFolder libraryFolder = await BooUtility.GetFolderFromDocumentFolderAsync(BooDocumentHelper.LibraryFolder);
            StorageFile file = await libraryFolder.CreateFileAsync(LanguageManager.NewDocument+Configuration.GlobalVariable.FileExtension, CreationCollisionOption.GenerateUniqueName);
            XmlElement CreateTime = xml.CreateElement("CreateTime");
            CreateTime.InnerText = file.DateCreated.DateTime.ToString();
            xmlroot.AppendChild(CreateTime);

            FileName.InnerText = file.Name;
            await file.DeleteAsync();

            StorageName.InnerText = BooUtility.GetUniqueName(".bpt");

            doc.FileName = file.Name;

            doc.summaryBlock.Load(xml.GetXml());

            return doc;
        }

        public static async Task<bool> SaveToFile(StorageFile file,BooDocumentInMemory memoryDocument,List<String> imageFiles)
        {
            if(GlobalVariable.ImageFolder == null)
                GlobalVariable.ImageFolder = await BooUtility.GetFolderFromDocumentFolderAsync(BooDocumentHelper.ImageFolder);
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                stream.Size = 0;
                using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
                {
                    
                    await memoryDocument.summaryBlock.WriteToArchive(writer);
                    
                    foreach (BPTFileBlock slide in memoryDocument.SlideBlocks)
                    {
                        await slide.WriteToArchive(writer);
                    }
                    foreach (String image in imageFiles)
                    {
                        if (image == "")
                            continue;

                        BPTFileBlock block = await BPTFileBlock.FromFileAsync(await BooDocumentFolderInformation.ImageResources.GetFileAsync(image));
                        block.GroupName = "images";
                        await block.WriteToArchive(writer);
                    }

                    await writer.StoreAsync();
                    await writer.FlushAsync();
                }
            }
            return false;
        }

        public static async Task<BPTFileInformation> GetThumbInformation(StorageFile file)
        {
            try
            {
                BPTFileInformation infomation = new BPTFileInformation();

                using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
                {
                    if (stream.Size == 0)
                        return null;
                    using (DataReader reader = new DataReader(stream.GetInputStreamAt(0)))
                    {
                        await reader.LoadAsync((uint)stream.Size);
                        BPTFileBlock summaryBlock = await BPTFileBlock.FromArchiveAsync(reader);

                        String text = System.Text.Encoding.UTF8.GetString(summaryBlock.ByteData, 0, summaryBlock.ByteData.Length);
                        String xmltext = text;
                        StringReader stringreader = new StringReader(xmltext);
                        XDocument xdoc = XDocument.Load(stringreader);

                        BPTFileBlock thumbImage = await BPTFileBlock.FromArchiveAsync(reader);
                        BitmapImage thumbBitmapImage = new BitmapImage();
                        if (thumbImage.Type == "thumb")
                        {
                            using (InMemoryRandomAccessStream thumbStream = new InMemoryRandomAccessStream())
                            {
                                using (DataWriter writer = new DataWriter(thumbStream.GetOutputStreamAt(0)))
                                {
                                    writer.WriteBytes(thumbImage.ByteData);
                                    await writer.StoreAsync();
                                    await writer.FlushAsync();
                                    thumbBitmapImage.SetSource(thumbStream);
                                }
                            }
                        }

                        infomation.FileName = file.Name;
                        infomation.UpdateTime = (await file.GetBasicPropertiesAsync()).DateModified.DateTime;
                        infomation.CreateTime = Convert.ToDateTime(xdoc.Element("BoolanPPT").Element("CreateTime").Value);
                        infomation.StorageName = xdoc.Element("BoolanPPT").Element("StorageName").Value;
                        infomation.Resolution = (BPTFileInformation.FileRatio)Convert.ToInt32(xdoc.Element("BoolanPPT").Element("Resolution").Value);
                        infomation.CoverImage = thumbBitmapImage;
                    }
                }

                return infomation;
            }
            catch (Exception exception)
            {
                return null;
            }
        }

        public static async Task<BooSlide> GetFirstSlideFromFile(StorageFile file)
        {
            BPTFileBlock slideBlock;
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
            {
                if (stream.Size == 0)
                    return null;

                using (DataReader reader = new DataReader(stream.GetInputStreamAt(0)))
                {
                    await reader.LoadAsync((uint)stream.Size);
                    while (true)
                    {
                        BPTFileBlock tmpBlock = await BPTFileBlock.FromArchiveAsync(reader);

                        if (tmpBlock == null)
                            return null;

                        if (tmpBlock.GroupName == "slides" && tmpBlock.FileName == "slide0.xml")
                        {
                            slideBlock = tmpBlock;
                            break;
                        }
                    }

                    using (InMemoryRandomAccessStream memStream = new InMemoryRandomAccessStream())
                    {
                        using (DataWriter writer = new DataWriter(memStream.GetOutputStreamAt(0)))
                        {
                            writer.WriteBytes(slideBlock.ByteData);
                            await writer.StoreAsync();
                            await writer.FlushAsync();
                            IInputStream output = memStream.GetInputStreamAt(0);
                            XDocument doc = XDocument.Load(output.AsStreamForRead());
                            BooSlide slide = BooSlideHelper.GenerateSlide(doc);
                            return slide;
                        }
                    }
                }
            }
        }
        public static async Task<bool> GetImageResourceFromFile(BooSlide slide, StorageFile file)
        {
            List<string> imagePath = new List<string>();
            Dictionary<string, BitmapImage> ImageResources = new Dictionary<string, BitmapImage>();
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read))
            {
                using (DataReader reader = new DataReader(stream.GetInputStreamAt(0)))
                {
                    await reader.LoadAsync((uint)stream.Size);

                    foreach (var item in slide.Elements)
                    {
                        if (item is BooPictureElement)
                        {
                            imagePath.Add((item as BooPictureElement).filePath);

                            if(ImageResources.Contains(new KeyValuePair<string,BitmapImage>((item as BooPictureElement).filePath, null)) == false)
                                ImageResources.Add((item as BooPictureElement).filePath, null);
                        }
                    }

                    bool BKGLoaded = false;

                    if (slide.BackgroundImagePath == "" || slide.BackgroundImagePath == null)
                        BKGLoaded = true;

                    while (true)
                    {
                        BPTFileBlock tmpBlock = await BPTFileBlock.FromArchiveAsync(reader);
                        if (tmpBlock == null)
                            break;
                        if ((tmpBlock.GroupName == "images" && imagePath.Contains(tmpBlock.FileName))||tmpBlock.FileName==slide.BackgroundImagePath)
                        {
                            bool isFileExist = false;
                            IReadOnlyList<StorageFile> files = await BooDocumentFolderInformation.ImageResources.GetFilesAsync();
                            foreach (var item in files)
                            {
                                if (tmpBlock.FileName == item.Name)
                                {
                                    isFileExist = true;
                                    break;
                                }
                            }
                            if (isFileExist)
                                continue;
                            StorageFile image = await BooDocumentFolderInformation.ImageResources.CreateFileAsync(tmpBlock.FileName);
                            using (IRandomAccessStream ranstream = await image.OpenAsync(FileAccessMode.ReadWrite))
                            {
                                using (DataWriter writer = new DataWriter(ranstream.GetOutputStreamAt(0)))
                                {
                                    writer.WriteBytes(tmpBlock.ByteData);
                                    await writer.StoreAsync();
                                    await writer.FlushAsync();
                                }
                            }
                            if (tmpBlock.FileName == slide.BackgroundImagePath)
                                BKGLoaded = true;
                            else
                                ImageResources.Remove(tmpBlock.FileName);

                            if (BKGLoaded == true && (ImageResources.Count <= 0 || tmpBlock == null))
                                break;
                        }
                    }
                }
            }
            return true;
        }
    }
}
